﻿#if NETSTANDARD2_1
using Exceptionless.Logging;
using nlgo =NLog;
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using NLog.Fluent;
using Exceptionless.NLog;
using CNative.Logging.Settings;
using CNative.Logging;

namespace CNative.Exceptionless.NLog
{
    public class ExceptionlessLogger : Microsoft.Extensions.Logging.ILogger, IExceptionlessLog
    {
        private string name;
        private readonly nlgo.Logger _logger = null;// nlgo.LogManager.GetCurrentClassLogger();

        public ExceptionlessLogger(string _name)
        {
            name = _name;

            _logger = nlgo.LogManager.GetLogger(_name);
            try
            {
                string isUseExceptionless = AppConfigurtaion.GetAppSettings("Exceptionless:UseExceptionless", "false");
                if (isUseExceptionless.ToLower() == "true" || isUseExceptionless == "1")
                {
                    var target = nlgo.LogManager.Configuration.FindTargetByName<nlgo.Targets.Wrappers.AsyncTargetWrapper>("exceptionless");
                    if (target != null && target.WrappedTarget is ExceptionlessTarget tg)
                    {
                        tg.ApiKey = AppConfigurtaion.GetAppSettings("Exceptionless:ApiKey");
                        tg.ServerUrl = AppConfigurtaion.GetAppSettings("Exceptionless:ServerUrl");

                        SettingsHelpers.InvokeMethod(tg, "InitializeTarget");

                        //var logLevel = AppConfigurtaion.GetAppSettings("Logging:LogLevel:DotNetCore.Exceptionless.NLog.ExceptionlessLogger", "Error");
                    }

                    //var sss = new List<nlgo.Config.LoggingRule>();
                    //for (var i = 0; i < nlgo.LogManager.Configuration.LoggingRules.Count; i++)
                    //{
                    //    var ru = nlgo.LogManager.Configuration.LoggingRules[i];
                    //    foreach (var tgg in ru.Targets)
                    //    {
                    //        if (tgg.Name.Contains("ElasticSearchWeb"))
                    //        {
                    //            sss.Add(ru);
                    //            break;
                    //        }
                    //    }
                    //}
                    //sss.ForEach(ru => nlgo.LogManager.Configuration.LoggingRules.Remove(ru));
                }
            }
            catch (Exception ex) { _logger.Error(ex); }
        }
        public IDisposable BeginScope<TState>(TState state)
        {
            return null;
        }
        public LogLevel MinimumLogLevel { get; set; }
        /// <summary>
        /// 判断是否开启记录
        /// </summary>
        public bool IsEnabled(Microsoft.Extensions.Logging.LogLevel logLevel)
        {
            var convertLogLevel = ConvertLogLevel(logLevel);
            return _logger.IsEnabled(convertLogLevel);
        }
        /// <summary>
        /// 实现接口ILogger
        /// </summary>
        /// <typeparam name="TState"></typeparam>
        /// <param name="logLevel"></param>
        /// <param name="eventId"></param>
        /// <param name="state"></param>
        /// <param name="exception"></param>
        /// <param name="formatter"></param>
        public void Log<TState>(Microsoft.Extensions.Logging.LogLevel logLevel, Microsoft.Extensions.Logging.EventId eventId, TState state, Exception exception, Func<TState, Exception, string> formatter)
        {
            if (!IsEnabled(logLevel))
            {
                return;
            }

            if (formatter == null)
            {
                throw new ArgumentNullException(nameof(formatter));
            }

            var message = formatter(state, exception);

            if (String.IsNullOrEmpty(message) && exception == null)
                return;

            // Add event id, if available
            if (eventId.Id != 0)
                _logger.SetProperty("EventId", eventId.Id);

            _logger.SetProperty("TimeStamp", DateTime.UtcNow);
            if (state != null)
            {
                //if (state is IDictionary<string, object> stateProps)
                //{
                //    var ei = new MyLogEventInfo(ConvertLogLevel(logLevel), message, stateProps);

                //    _logger.Log(ei);
                //    return;
                //}
                if (state is IEnumerable<KeyValuePair<string, object>> stateProps)
                {
                    foreach (var prop in stateProps)
                    {
                        // Logging the message template is superfluous
                        _logger.SetProperty(prop.Key, prop.Value);
                    }
                }
                else
                {
                    // Otherwise, attach the entire object, using its type as the name
                    _logger.SetProperty("Tags", state.ToString());
                }
            }

            switch (logLevel)
            {
                case Microsoft.Extensions.Logging.LogLevel.Critical://致命错误
                    //_logger.Fatal(message);
                    Fatal(message, null, exception);
                    break;
                case Microsoft.Extensions.Logging.LogLevel.Debug:
                    //_logger.Debug(message);
                    Debug(message);
                    break;
                case Microsoft.Extensions.Logging.LogLevel.Trace://追踪
                    //_logger.Trace(message);
                    Trace(message);
                    break;
                case Microsoft.Extensions.Logging.LogLevel.Error:
                    //_logger.Error(message);
                    Error(message,null, exception);
                    break;
                case Microsoft.Extensions.Logging.LogLevel.Information:
                    //_logger.Info(message);
                    Info(message);
                    break;
                case Microsoft.Extensions.Logging.LogLevel.Warning:
                    //_logger.Warn(message);
                    Warn(message);
                    break;
                default:
                    //_logger.Info(message);
                    Info(message);
                    break;
            }
        }

        public nlgo.LogLevel ConvertLogLevel(Microsoft.Extensions.Logging.LogLevel logLevel)
        {
            switch (logLevel)
            {
                case Microsoft.Extensions.Logging.LogLevel.Trace:
                    return nlgo.LogLevel.Trace;
                case Microsoft.Extensions.Logging.LogLevel.Debug:
                    return nlgo.LogLevel.Debug;
                case Microsoft.Extensions.Logging.LogLevel.Information:
                    return nlgo.LogLevel.Info;
                case Microsoft.Extensions.Logging.LogLevel.Warning:
                    return nlgo.LogLevel.Warn;
                case Microsoft.Extensions.Logging.LogLevel.Error:
                    return nlgo.LogLevel.Error;
                case Microsoft.Extensions.Logging.LogLevel.Critical:
                    return nlgo.LogLevel.Fatal;
                case Microsoft.Extensions.Logging.LogLevel.None:
                    return nlgo.LogLevel.Off;
                default:
                    return nlgo.LogLevel.Debug;
            }
        }

        public void Error(string message, string source = null, Exception exception = null)
        {
            if (!IsEnabled(Microsoft.Extensions.Logging.LogLevel.Error))
                return;

            _logger.Error().Message(message).LoggerName(source).Exception(exception).Write();
        }
        public void Fatal(string message, string source = null, Exception exception = null)
        {
            if (!IsEnabled(Microsoft.Extensions.Logging.LogLevel.Critical))
                return;

            _logger.Fatal().Message(message).LoggerName(source).Exception(exception).Write();
        }

        public void Info(string message, string source = null)
        {
            if (!IsEnabled(Microsoft.Extensions.Logging.LogLevel.Information))
                return;

            _logger.Info().Message(message).LoggerName(source).Write();
        }

        public void Debug(string message, string source = null)
        {
            if (!IsEnabled(Microsoft.Extensions.Logging.LogLevel.Debug))
                return;

            _logger.Debug().Message(message).LoggerName(source).Write();
        }

        public void Warn(string message, string source = null)
        {
            if (!IsEnabled(Microsoft.Extensions.Logging.LogLevel.Warning))
                return;

            _logger.Warn().Message(message).LoggerName(source).Write();
        }

        public void Trace(string message, string source = null)
        {
            if (!IsEnabled(Microsoft.Extensions.Logging.LogLevel.Trace))
                return;

            _logger.Trace().Message(message).LoggerName(source).Write();
        }

        public void Flush() { }
    }
}
#endif